import re

import httpx
import numpy as np
import sounddevice as sd
from typing import List

# 配置参数
API_KEY = "icoolkj-3d2d71e2a20a4b1a95269db9f3f32c9c"
API_URL = "https://edgetts.api.icoolkj.cn/v1/audio/speech"
VOICE = "zh-CN-XiaoxiaoNeural" # 语音角色
SPEED = 1.0 # 语速
TEXT_CHUNK_SIZE = 50 # 文本分块大小
SAMPLE_RATE = 24000 # Edge-TTS 音频采样率（固定240000Hz）

def split_text(text: str, chunk_size: int = TEXT_CHUNK_SIZE) -> List[str]:
    """智能分段：按标点拆分，清理空白，确保每段非空"""
    # 1、清理文本（去除多余空白、换行）
    text = text.strip().replace("\n", " ") .replace("  ", " ")
    # 2、按标点符号拆分（优先在逗号、句号处断句，更自然）
    chunks = re.split(r'([，；。！？,;.!?]\s)',  text)
    # 3、合并拆分的片段，避免过短
    merged = []
    current = ""
    for chunk in chunks:
        if len(current) + len(chunk) < chunk_size:
            current += chunk
        else:
            if current:
                merged.append(current.strip())
            current = chunk
    if current:
        merged.append(current.strip())
    # 4、过滤空片段
    return [c for c in merged if c]

def play_audio(audio_bytes: bytes):
    """
    播放音频字节流（需转换为numpy数组）
    """
    # 将MP3字节流转换为可播放的音频数组（需安装ffmpeg支持MP3解码）
    # 若转换失败，可尝试先保存为临时文本再播放
    try:
        import soundfile as sf
        from io import BytesIO
        # 用soundfile库将MP3字节流转换为numpy数组（依赖ffmpeg）
        audio_data, _ = sf.read(BytesIO(audio_bytes), dtype='int16')
        # 播放音频（单声道转双声道，避免部分设备不支持单声道）
        if audio_data.ndim == 1:
            audio_data = np.repeat(audio_data[:, np.newaxis], 2, axis=1)
        sd.play(audio_data, samplerate=SAMPLE_RATE, blocking=True)
        sd.wait() # 等待音频播放完毕
    except Exception as e:
        print(f"音频播放失败：{e}")
        # 备选方案：保存为临时文件并播放
        with open("temp_audio.mp3", "wb") as f:
            f.write(audio_bytes)
        import os
        os.system(f"mpg123 temp_audio.mp3") # 需安装ffmpeg

async def realtime_tts(text: str):
    """
    实时语音播报主函数：分段请求API并播放
    """
    chunks = split_text(text)
    if not chunks:
        print("没有可播放的文本")
        return

    async with httpx.AsyncClient() as client:
        for i, chunk in enumerate(chunks):
            print(f"正在播报第 {i+1}/{len(chunks)} 段: {chunk}")
            headers = {
                "Authorization": f"Bearer {API_KEY}",
                "Content-Type": "application/json"
            }
            params = {
                "model": "tts-1",
                "input": chunk,
                "voice": VOICE,
                "speed": SPEED,
                "response_format": "mp3"
            }
            try:
                # 调用API获取当前块的音频数据
                response = await client.post(API_URL, headers=headers, json=params, timeout=30)
                if response.status_code != 200:
                    print(f"API请求失败（段{i+1}），状态码：{response.status_code}，响应内容：{response.text}")
                    continue

                # 播放当前段的音频
                play_audio(response.content)
            except Exception as e:
                print(f"API请求异常（段{i+1}）：{e}")
                continue

# 测试
if __name__ == "__main__":
    import asyncio
    test_text = """
       欢迎大家关注旺旺小布丁的小红书！这里会分享超多实用的生活技巧、好物推荐，
       还有各种有趣的日常vlog。希望大家喜欢我的内容，记得点赞收藏加关注哦，
       你们的支持就是我更新的最大动力！后续还会有更多精彩内容，不要错过啦～
       """
    # 运行实时播报
    asyncio.run(realtime_tts(test_text))
